#pragma once 

#include <time.h>
#include <string.h>
#include <iostream>
#include <string>

//获取时间戳
class TimeStamp
{
    public:
        //被static修饰的方法属于类方法，可以通过[类名.成员函数名]直接引用，而不需要new出一个类来
        static void GetTimeStamp(std::string* timestamp)
        {
            //time函数   time_t time(time_t *t);
            //获取从1970年1月1日开始的秒数
            time_t sys_time;
            time(&sys_time);

            //struct tm *localtime(const time_t *timep);
            //将秒数转换成为：年-月-日 时:分:秒
            struct tm *t = localtime(&sys_time); //注意返回值

            //将这个时间[年月日时分秒]放到timestamp当中
            //不好直接放到string对象当中
            //用c语言的方式将这个时间格式化到一个buf当中
            //最后将buf追加到string对象当中去
            char buf[30] = {'\0'}; //30个绰绰有余， yyyy-mm-dd hh-mm-ss 
            snprintf(buf, sizeof(buf) - 1, "%04d-%02d-%02d %02d:%02d:%02d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
            //年是从1900年以后算的，所以要加1900
            //月是0-11,所以要加1
            timestamp->assign(buf, strlen(buf));
        }
};

//采用枚举，方便后期扩展
//日志等级
enum LogLevel
{
    INFO = 0,
    WARNING,
    ERROR,
    FATAL,
    DEBUG
};

//字符指针数组
//字符指针数组的值就对应枚举中的值
const char* LevelInfo[] = 
{
    "INFO",
    "WARNING",
    "ERROR",
    "FATAL",
    "DEBUG"
};

//接下来就是写日志
//loglevel:日志等级
//file:源码文件名称，日志在哪一个文件
//line:源码当中对应的代码行
//msg:需要记录的具体信息
//
//日志格式：[时间戳 等级 源文件名称：行号]  具体信息
//__FILE__:宏，获取文件名称
//__LINE__:宏，获取行数
std::ostream& Log(LogLevel loglevel, const char* file, int line, const std::string& msg) //给一个引用，想看日志的话，直接调用Log
{
    //ostream：标准输出流
    std::string timestamp; 
    TimeStamp::GetTimeStamp(&timestamp);

    std::string level = LevelInfo[loglevel]; //level即拿到下标为loglevel的字符串
    std::cout << "[" << timestamp << " " << level << " " << file << ":" << line << "]"<< " " << msg;
    return std::cout;
}

//每次都要传入__FILE__与__LINE__比较耗时，可以定义一个宏只传入loglevel和msg即可
#define LOG(loglevel, msg) Log(loglevel, __FILE__, __LINE__, msg) 
